package com.sinosoft.hydra.um.services.component.dataoutput;

import cn.com.sinux.spring.exception.ServiceException;
import cn.com.sinux.spring.utils.DateUtils;
import cn.com.sinux.spring.utils.FileUtils;
import com.sinosoft.hydra.logging.LogModules;
import com.sinosoft.hydra.um.services.component.dataoutput.test.ExcelInfo;
import jxl.Workbook;
import jxl.WorkbookSettings;
import jxl.format.*;
import jxl.format.Colour;
import jxl.read.biff.BiffException;
import jxl.write.*;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * Created by Administrator on 2015/8/25.
 */
public class ExcelDataWriter<T> implements DataWriter<T> {

    private RowTemplate<T> rowTemplate;
//    private ExcelType excelType;
    //    private Workbook workbook;
    private WritableWorkbook book;

//    public static enum ExcelType {
//        EXCEL_TYPE_2003,
//        EXCEL_TYPE_2007
//    }

    public ExcelDataWriter(RowTemplate<T> rowTemplate) {
        this.rowTemplate = rowTemplate;
    }
//
//    public ExcelDataWriter(RowTemplate<T> rowTemplate, ExcelType excelType) {
//        this.rowTemplate = rowTemplate;
//        this.excelType = excelType;
//        buildWorkbook();
//    }

//    @Deprecated
//    public void buildWorkbook() {
//        switch (this.excelType) {
//            case EXCEL_TYPE_2003:
//                this.workbook = new HSSFWorkbook();
//                break;
//            case EXCEL_TYPE_2007:
//                this.workbook = new XSSFWorkbook();
//                break;
//            default:
//                this.workbook = new HSSFWorkbook();
//                break;
//        }
//    }

    public String createName(String path){
        int last = path.lastIndexOf(".");
        return path.substring(0, last) + "1" + path.substring(last);
    }

    public void write(String path, List<T> objs) throws IOException, WriteException {
        File file = new File(path);
        WorkbookSettings wbSetting = new WorkbookSettings();
        wbSetting.setUseTemporaryFileDuringWrite(true);
        wbSetting.setTemporaryFileDuringWriteDirectory(file.getParentFile());//临时文件夹的位置
        this.book = jxl.Workbook.createWorkbook(file, wbSetting);
        List<RowTemplate.ColumnTemplate<T>> templates = rowTemplate.getColumnTemplates();
        int row = 1, l = templates.size();
        WritableSheet sheet = book.createSheet("sheet" + 0, 0);
        WritableFont headFont = new WritableFont(WritableFont.TIMES, 12, WritableFont.NO_BOLD, false, UnderlineStyle.NO_UNDERLINE,
                jxl.format.Colour.WHITE);
        WritableCellFormat wcf_title = new WritableCellFormat(headFont);
        wcf_title.setBackground(Colour.GREY_50_PERCENT); // 设置单元格的背景颜色
        WritableFont countents = new WritableFont(WritableFont.TIMES, 12);
        WritableCellFormat wcf_table = new WritableCellFormat(countents);
        for (int j = 0; j < l; j++) {
            sheet.addCell(new Label(j, 0, templates.get(j).getTitle(), wcf_title));
        }
        List<WritableSheet> sheets = new ArrayList<WritableSheet>();
        sheets.add(sheet);
        int size = objs.size();
        int pages = size / 30000 + (size % 30000 > 0 ? 1 : 0);
        for (int page = 1; page < pages; page++) {
            sheets.add(book.createSheet("sheet" + (page + 1), page + 1));
        }
        try {
            for (int page = 0; page < pages; page++) {
                int end = (page + 1) * 30000;
                end = end > size ? size : end;
                List<T> shorts = objs.subList(page * 30000, end);
                for (T t : shorts) {
                    for (int j = 0; j < l; j++) {
                        WritableCell writableCell = templates.get(j).getColumnParser().parse(row, j, t);
                        writableCell.setCellFormat(wcf_table);
                        sheets.get(page).addCell(writableCell);
                    }
                    row++;
                }
                row = 0;
            }
            book.write();
        }catch (Exception ex){
            LoggerFactory.getLogger(LogModules.STD_LOGGER).error("生成数据失败，发生IO错误");
        }finally {
            book.close();
        }
    }

    @Deprecated
    public void write(OutputStream outputStream, List<T> objs) throws IOException, WriteException {
        this.book = jxl.Workbook.createWorkbook(outputStream);
        List<RowTemplate.ColumnTemplate<T>> templates = rowTemplate.getColumnTemplates();
        int row = 1, l = templates.size();
        WritableSheet sheet = book.createSheet("sheet" + 0, 0);
        WritableFont headFont = new WritableFont(WritableFont.TIMES, 12, WritableFont.NO_BOLD, false, UnderlineStyle.NO_UNDERLINE,
                jxl.format.Colour.WHITE);
        WritableCellFormat wcf_title = new WritableCellFormat(headFont);
        wcf_title.setBackground(Colour.GREY_50_PERCENT); // 设置单元格的背景颜色
        WritableFont countents = new WritableFont(WritableFont.TIMES, 12);
        WritableCellFormat wcf_table = new WritableCellFormat(countents);
        for (int j = 0; j < l; j++) {
            sheet.addCell(new Label(j, 0, templates.get(j).getTitle(), wcf_title));
        }
        int size = objs.size();
        int pages = size / 50000 + (size % 50000 > 0 ? 1 : 0);
        for (int page = 0; page < pages; page++) {
            int end = (page + 1) * 50000;
            end = end > size ? size : end;
            List<T> shorts = objs.subList(page * 50000, end);
            for (T t : shorts) {
                for (int j = 0; j < l; j++) {
                    WritableCell writableCell = templates.get(j).getColumnParser().parse(row, j, t);
                    writableCell.setCellFormat(wcf_table);
                    sheet.addCell(writableCell);
                }
                row++;
            }
            row = 0;
            book.write();
            book.close();
            sheet = book.createSheet("sheet" + (page + 1), page + 1);
        }
        try {
            book.close();
        } catch (IOException e) {
            LoggerFactory.getLogger(LogModules.STD_LOGGER).error("生成数据失败，发生IO错误");
        }
    }

    public byte[] write(List<T> objs) throws IOException, WriteException {
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        write(os, objs);
        return os.toByteArray();
    }


//    @Deprecated
//    public void write(OutputStream outputStream, List<T> objs) {
//        Sheet sheet = this.workbook.createSheet();
//        List<RowTemplate.ColumnTemplate<T>> templates = rowTemplate.getColumnTemplates();
//        int i = 0, l = templates.size();
//        Row row = sheet.createRow(i);
//        //创建标题
//        CellStyle style = this.workbook.createCellStyle();
//        style.setFillForegroundColor(IndexedColors.GREY_40_PERCENT.getIndex());
//        style.setFillPattern(CellStyle.SOLID_FOREGROUND);
//        style.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);
//        style.setAlignment(HSSFCellStyle.ALIGN_CENTER);
//
//        Font font = this.workbook.createFont();
//        font.setColor(IndexedColors.WHITE.getIndex());
//        font.setFontName("宋体");
//        font.setFontHeightInPoints((short) 11);
//        style.setFont(font);
//
//        CellStyle style2 = this.workbook.createCellStyle();
//        Font font2 = this.workbook.createFont();
//        font2.setFontHeightInPoints((short) 11);
//        style.setFont(font2);
//
//        for (int j = 0; j < l; j++) {
//            sheet.setColumnWidth(j, 4000);
//            Cell cell = row.createCell(j);
//            cell.setCellStyle(style);
//            cell.setCellValue(templates.get(j).getTitle());
//        }
//        int size = objs.size();
//        int pages = size / 60000 + (size % 60000 > 0 ? 1 : 0);
//        i++;
//        for (int page = 0; page < pages; page++) {
//            int end = (page + 1) * 60000;
//            end = end > size ? size : end;
//            List<T> shorts = objs.subList(page * 60000, end);
//            for (T t : shorts) {
//                row = sheet.createRow(i);
//                for (int j = 0; j < l; j++) {
//                    Cell cell = row.createCell(j);
//                    cell.setCellStyle(style2);
//                    templates.get(j).getColumnParser().parse(cell, t);
//                }
//                i++;
//            }
//            sheet = this.workbook.createSheet();
//        }
//        try {
//            workbook.write(outputStream);
//        } catch (IOException e) {
//            LoggerFactory.getLogger(LogModules.STD_LOGGER).error("生成数据失败，发生IO错误");
//        }
//    }

//    @Deprecated
//    public byte[] write(List<T> objs) {
//        ByteArrayOutputStream os = new ByteArrayOutputStream();
//        write(os, objs);
//        return os.toByteArray();
//    }

    /**
     * 导出Excel文件
     *
     * @param excelInfo
     * @return
     */
    public static <T> HSSFWorkbook exportExcel(ExcelInfo excelInfo, List<T> datas) {
        HSSFWorkbook wb = new HSSFWorkbook();
        HSSFSheet sheet = wb.createSheet("sheet0");
        try {
            //获取模板中的标题，属性以及对应的属性
            String templates = excelInfo.getTemplate();
            String[] template = templates.split(";");
            List<String> titles = new ArrayList<String>();
            List<String> fields = new ArrayList<String>();
            List<String> types = new ArrayList<String>();
            for (String str : template) {
                String[] values = str.split("=");
                titles.add(values[0]);
                fields.add(values[1]);
                types.add(values[2]);
            }
            //设置标题
            outputHeaders(titles, sheet, wb);
            //设置单元格内容
            outputColumns(fields, types, datas, sheet, 1, excelInfo);
        } catch (Exception e) {
            throw new ServiceException(e.getMessage() + "前台模板数据错误！");
        }
        return wb;
    }

    /**
     * 导出Excel文件（多个sheet）
     *
     * @param excelInfo
     * @return
     */
    public static <T> HSSFWorkbook exportExcelSheets(ExcelInfo excelInfo, Map<String, List<T>> sheets) {
        HSSFWorkbook wb = new HSSFWorkbook();
        for (Map.Entry<String, List<T>> entry : sheets.entrySet()) {
            HSSFSheet sheet = wb.createSheet(entry.getKey());
            try {
                //获取模板中的标题，属性以及对应的属性
                String templates = excelInfo.getTemplate();
                String[] template = templates.split(";");
                List<String> titles = new ArrayList<String>();
                List<String> fields = new ArrayList<String>();
                List<String> types = new ArrayList<String>();
                for (String str : template) {
                    String[] values = str.split("=");
                    titles.add(values[0]);
                    fields.add(values[1]);
                    types.add(values[2]);
                }
                //设置标题
                outputHeaders(titles, sheet, wb);
                //设置单元格内容
                outputColumns(fields, types, entry.getValue(), sheet, 1, excelInfo);
            } catch (Exception e) {
                throw new ServiceException(e.getMessage() + "前台模板数据错误！");
            }
        }
        return wb;
    }

    /**
     * 设置sheet表头信息
     *
     * @param headersInfo
     * @param sheet
     * @author David
     */
    private static void outputHeaders(List<String> headersInfo, HSSFSheet sheet, HSSFWorkbook wb) {
        HSSFRow row = sheet.createRow(0);
        for (int i = 0; i < headersInfo.size(); i++) {
            sheet.setColumnWidth(i, 4000);
            Cell cell = row.createCell(i);
            HSSFCellStyle style = wb.createCellStyle();
            style = wb.createCellStyle();
            style.setFillForegroundColor(IndexedColors.GREY_40_PERCENT.getIndex());
            style.setFillPattern(CellStyle.SOLID_FOREGROUND);
            HSSFFont font = wb.createFont();
            style.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);
            style.setAlignment(HSSFCellStyle.ALIGN_CENTER);
            font.setFontName("宋体");
            font.setFontHeightInPoints((short) 14);
            cell.setCellStyle(style);
            cell.setCellValue(headersInfo.get(i));
        }
    }

    /**
     * 获取内容
     *
     * @param fieldInfo
     * @param columnsInfo
     * @param sheet
     * @param rowIndex
     */
    private static void outputColumns(List<String> fieldInfo, List<String> typesInfo, List columnsInfo, HSSFSheet sheet, int rowIndex , ExcelInfo excelInfo) {
        HSSFRow row;
        //循环插入多少行
        for (int i = 0; i < columnsInfo.size(); i++) {
            row = sheet.createRow(rowIndex + i);
            Object obj = columnsInfo.get(i);
            //循环每行多少列
            for (int j = 0; j < fieldInfo.size(); j++) {
                Object value = getFieldValueByName(fieldInfo.get(j), obj);
                String type = typesInfo.get(j);
                String str ;
                if(j == 0 && excelInfo.isSortNum()){
                    str = String.valueOf(i + 1);
                }else {
                    str = value != null ? getValueWithType(type, value) : "";
                }
                try {
                    double data = Double.valueOf(str);
                    row.createCell(j).setCellValue(data);
                }catch (Exception e){
                    row.createCell(j).setCellValue(str);
                }
            }
        }

    }

    /**
     * 根据对象的属性获取值
     *
     * @param fieldName
     * @param obj
     * @return
     * @author David
     */
    private static Object getFieldValueByName(String fieldName, Object obj) {
        //判断属性是否为其他对象中的属性
        if (fieldName.contains(".")) {
            String[] fieldNames = fieldName.split("\\p{Punct}");
            for (String field : fieldNames) {
                obj = getFieldValueByNames(field, obj);
            }
            return obj;
        }
        return getFieldValueByNames(fieldName, obj);
    }

    private static Object getFieldValueByNames(String fieldName, Object obj) {
        String firstLetter = fieldName.substring(0, 1).toUpperCase();
        String getter = "get" + firstLetter + fieldName.substring(1);
        try {
            Method method = obj.getClass().getMethod(getter, new Class[]{});
            Object value = method.invoke(obj, new Object[]{});
            return value;
        } catch (Exception e) {
            return null;
        }
    }

    private static String getValueWithType(String type, Object value) {
        if (type.contains("[")) {
            String formateStr = type.substring(type.indexOf("[") + 1, type.lastIndexOf("]"));
            if ("date".equals(type.substring(0, type.indexOf("[")))) {
                Date date = (Date) value;
                if(formateStr.contains("-mm-")){
                    formateStr = formateStr.replace("-mm-","-MM-");
                }
                String str = DateUtils.formatDate(date, formateStr);
                return str;
            } else if ("enum".equals(type.substring(0, type.indexOf("[")))) {
                String[] values = formateStr.split("&");
                for (String str : values) {
                    String[] keyAndValue = str.split(":");
                    if (value.toString().equals(keyAndValue[0])) {
                        return keyAndValue[1];
                    }

                }
            }

        }
        return value.toString();
    }

}
